package com.ljx.blog.security.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.ljx.blog.security.common.UserContext;
import com.ljx.blog.user.domain.dto.UserDto;
import com.ljx.blog.user.domain.entity.*;
import com.ljx.blog.user.domain.vo.resp.UserResp;
import com.ljx.blog.user.enums.TenantRoleEnum;
import com.ljx.blog.user.service.*;
import com.ljx.blog.common.constant.CacheConstants;
import com.ljx.blog.common.exception.ApiException;
import com.ljx.blog.common.util.RedisUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2024-10-02  00:14
 */
public class UserUtil {

    public static void setUserCache(UserResp userResp) {
        RedisUtil.set(CacheConstants.getKey(CacheConstants.USER_INFO, userResp.getId()),
                JSONUtil.toJsonStr(userResp), CacheConstants.USER_INFO_EXPIRE_TIME, TimeUnit.HOURS);
    }

    public static UserResp getUserCache(Long userId) {
        return JSONUtil.toBean(RedisUtil.get(CacheConstants.getKey(CacheConstants.USER_INFO, userId)), UserResp.class);
    }

    private static final String SECRET = "eyJqdGkiOiI0MDQiLCJzdWIiOiLpgqLnq4vosbkiL";

    public static String createToken(Long userId, Long tokenId) {
        Map<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        map.put("tokenId", tokenId);
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .setClaims(map)
                .compact();
    }

    public static void setTokenCache(UserDto userDto, Long tokenId) {
        RedisUtil.set(CacheConstants.getKey(CacheConstants.LOGIN_TOKEN_KEY, tokenId), JSONUtil.toJsonStr(userDto),
                CacheConstants.LOGIN_TOKEN_KEY_EXPIRE_TIME, TimeUnit.HOURS);
    }

    public static UserDto getTokenCache(Long tokenId) {
        return JSONUtil.toBean(RedisUtil.get(CacheConstants.getKey(CacheConstants.LOGIN_TOKEN_KEY, tokenId)), UserDto.class);
    }

    public static UserDto parseToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET)
                .parseClaimsJws(token)
                .getBody();
        Long tokenId = Long.parseLong(claims.get("tokenId").toString());
        String userStr = RedisUtil.get(CacheConstants.getKey(CacheConstants.LOGIN_TOKEN_KEY, tokenId));
        if (StrUtil.isEmpty(userStr)) {
            throw new ApiException("身份解析失败");
        }
        return JSONUtil.toBean(userStr, UserDto.class);
    }

    public static List<Role> tryToGetUserRole(Long userId) {
        RoleService roleService = SpringUtil.getBean(RoleService.class);
        List<Long> roleIds = roleService.getUserRoleIdByUserId(userId);
        if (roleIds.isEmpty()){
            return new ArrayList<>();
        }
        return roleService.getRoleByIds(roleIds);
    }

    public static List<Permission> tryToGetUserPermission(Long userId) {
        PermissionService permissionService = SpringUtil.getBean(PermissionService.class);
        List<Long> roles = tryToGetUserRole(userId).stream().map(Role::getId).collect(Collectors.toList());
        if (roles.isEmpty()){
            return new ArrayList<>();
        }
        List<Long> permissionByRoleIds = permissionService.getPermissionIdByRoleIds(roles);
        return permissionService.getPermissionByIds(permissionByRoleIds);
    }

    public static List<Menu> tryToGetUserMenu(Long userId) {
        MenuService menuService = SpringUtil.getBean(MenuService.class);
        List<Long> roles = tryToGetUserRole(userId).stream().map(Role::getId).collect(Collectors.toList());
        if (roles.isEmpty()){
            return new ArrayList<>();
        }
        List<Long> menuIds = menuService.getMenuIdByRoleIds(roles);
        return menuService.getMenuByIds(menuIds);
    }

    public static UserDto getUserInfo(){
        return UserContext.getUser();
    }

    public static Long getUserId(){
        return getUserInfo().getId();
    }

    public static Long tryToGetUserTenantId(Long userId){
        UserService userService = SpringUtil.getBean(UserService.class);
        User user = userService.getById(userId);
        return user.getTenantId();
    }

    public static Long tryToGetTenantId(){
        Long tenantId = UserContext.getTenantId();
        if (Objects.isNull(tenantId)){
            throw new ApiException("租户参数不能为空");
        }
        return tenantId;
    }

    public static void checkIsSameTenant() {
        UserService userService = SpringUtil.getBean(UserService.class);
        Long tenantId = UserUtil.tryToGetTenantId();
        User user = userService.getById(UserUtil.getUserId());
        if (Objects.isNull(tenantId) || Objects.isNull(user) || !user.getTenantId().equals(tenantId)){
            throw new ApiException("权限不足");
        }
    }

    public static Boolean checkIsTenantAdmin(){
        Long tenantId = UserUtil.tryToGetTenantId();
        TenantService tenantService = SpringUtil.getBean(TenantService.class);
        RoleService roleService = SpringUtil.getBean(RoleService.class);
        Tenant tenant = tenantService.getById(tenantId);
        return roleService.checkUserRole(UserUtil.getUserId(), TenantRoleEnum.getAdminCode(tenant.getCode()));
    }

    public static Boolean checkIsPlatform(){
        for (Role role : UserUtil.getUserInfo().getRoles()) {
            if (role.getName().equals(TenantRoleEnum.PLATFORM.getKey())){
                return true;
            }
        }
        return false;
    }
}
